package com.ruoyi.web.controller.redis;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Component
public class RedisUtilsTwo {
    private final RedisTemplate<String, Object> redisTemplate;
    private static final ObjectMapper objectMapper = new ObjectMapper();

    // 条件操作符常量
    public static final String OP_EQ = "eq";    // 等于
    public static final String OP_NE = "ne";    // 不等于
    public static final String OP_GT = "gt";    // 大于
    public static final String OP_LT = "lt";    // 小于
    public static final String OP_GTE = "gte";  // 大于等于
    public static final String OP_LTE = "lte";  // 小于等于

    @Autowired
    public RedisUtilsTwo(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    /**
     * 创建存储构建器
     */
    public Builder builder() {
        return new Builder(redisTemplate);
    }

    /**
     * 构建器类
     */
    public static class Builder {
        private final RedisTemplate<String, Object> redisTemplate;
        private String keyPrefix;
        private String indexKey;
        private List<Object> dataList;
        private Function<Object, String> keyExtractor;
        private Function<Object, String> fieldExtractor;
        private String secondaryIndex;
        private long expireTime;

        private Builder(RedisTemplate<String, Object> redisTemplate) {
            this.redisTemplate = redisTemplate;
        }

        public Builder keyPrefix(String keyPrefix) {
            this.keyPrefix = keyPrefix;
            return this;
        }

        public Builder indexKey(String indexKey) {
            this.indexKey = indexKey;
            return this;
        }

        public Builder dataList(List<Object> dataList) {
            this.dataList = dataList;
            return this;
        }

        public Builder keyExtractor(Function<Object, String> keyExtractor) {
            this.keyExtractor = keyExtractor;
            return this;
        }

        public Builder fieldExtractor(Function<Object, String> fieldExtractor) {
            this.fieldExtractor = fieldExtractor;
            return this;
        }

        public Builder secondaryIndex(String secondaryIndex) {
            this.secondaryIndex = secondaryIndex;
            return this;
        }

        public Builder expireTime(long expireTime) {
            this.expireTime = expireTime;
            return this;
        }

        /**
         * 批量存储数据到Redis
         */
        public void store() {
            if (CollectionUtils.isEmpty(dataList)) {
                return;
            }

            RedisSerializer<String> stringSerializer = new StringRedisSerializer();

            redisTemplate.executePipelined((RedisCallback<Object>) connection -> {
                for (Object data : dataList) {
                    try {
                        String keySuffix = keyExtractor.apply(data);
                        String key = keyPrefix + ":" + keySuffix;
                        String dataJson = objectMapper.writeValueAsString(data);

                        byte[] keyBytes = stringSerializer.serialize(key);
                        byte[] fieldBytes = stringSerializer.serialize("data");
                        byte[] valueBytes = stringSerializer.serialize(dataJson);

                        if (keyBytes != null && fieldBytes != null && valueBytes != null) {
                            connection.hSet(keyBytes, fieldBytes, valueBytes);

                            byte[] indexKeyBytes = stringSerializer.serialize(indexKey);
                            if (indexKeyBytes != null) {
                                connection.sAdd(indexKeyBytes, keyBytes);
                            }

                            if (expireTime > 0) {
                                connection.expire(keyBytes, expireTime);
                            }
                        }
                    } catch (Exception e) {
                        throw new RuntimeException("序列化对象失败", e);
                    }
                }

                if (expireTime > 0) {
                    byte[] indexKeyBytes = stringSerializer.serialize(indexKey);
                    if (indexKeyBytes != null) {
                        connection.expire(indexKeyBytes, expireTime);
                    }
                }
                return null;
            });
        }

        /**
         * 批量存储数据到Redis，并为指定字段创建二级索引
         */
        public void storeWithSecondaryIndex() {
            if (CollectionUtils.isEmpty(dataList) || fieldExtractor == null || secondaryIndex == null) {
                throw new IllegalArgumentException("缺少必要的参数: dataList, fieldExtractor 或 secondaryIndex");
            }

            RedisSerializer<String> stringSerializer = new StringRedisSerializer();

            redisTemplate.executePipelined((RedisCallback<Object>) connection -> {
                for (Object data : dataList) {
                    try {
                        String keySuffix = keyExtractor.apply(data);
                        String key = keyPrefix + ":" + keySuffix;
                        String dataJson = objectMapper.writeValueAsString(data);
                        String fieldValue = fieldExtractor.apply(data);
                        String secondaryIndexKey = secondaryIndex + ":" + fieldValue;

                        byte[] keyBytes = stringSerializer.serialize(key);
                        byte[] fieldBytes = stringSerializer.serialize("data");
                        byte[] valueBytes = stringSerializer.serialize(dataJson);

                        if (keyBytes != null && fieldBytes != null && valueBytes != null) {
                            connection.hSet(keyBytes, fieldBytes, valueBytes);

                            byte[] indexKeyBytes = stringSerializer.serialize(indexKey);
                            if (indexKeyBytes != null) {
                                connection.sAdd(indexKeyBytes, keyBytes);
                            }

                            byte[] secondaryIndexKeyBytes = stringSerializer.serialize(secondaryIndexKey);
                            if (secondaryIndexKeyBytes != null) {
                                connection.sAdd(secondaryIndexKeyBytes, keyBytes);

                                if (expireTime > 0) {
                                    connection.expire(secondaryIndexKeyBytes, expireTime);
                                }
                            }

                            if (expireTime > 0) {
                                connection.expire(keyBytes, expireTime);
                            }
                        }
                    } catch (Exception e) {
                        throw new RuntimeException("序列化对象失败", e);
                    }
                }

                if (expireTime > 0) {
                    byte[] indexKeyBytes = stringSerializer.serialize(indexKey);
                    if (indexKeyBytes != null) {
                        connection.expire(indexKeyBytes, expireTime);
                    }
                }
                return null;
            });
        }

        /**
         * 分页查询数据（支持多种条件）
         */
        public PageResult<String> pageQuery(int pageNum, int pageSize, Map<String, Object> conditions) {
            return pageQuery(pageNum, pageSize, conditions, null, true);
        }

        /**
         * 分页查询数据（带排序）
         */
        public PageResult<String> pageQuery(int pageNum, int pageSize,
                                            Map<String, Object> conditions,
                                            String sortField, boolean isAscending) {
            if (pageNum < 1) pageNum = 1;
            if (pageSize < 1) pageSize = 10;

            long start = (pageNum - 1) * pageSize;

            try {
                // 获取所有键
                Set<String> keys = redisTemplate.opsForSet().members(indexKey)
                        .stream()
                        .map(obj -> (String) obj)
                        .collect(Collectors.toSet());

                if (CollectionUtils.isEmpty(keys)) {
                    return new PageResult<>(Collections.emptyList(), 0, pageNum, pageSize);
                }

                // 批量获取原始JSON数据
                List<String> allJsonData = new ArrayList<>();
                for (String key : keys) {
                    Object value = redisTemplate.opsForHash().get(key, "data");
                    if (value != null) {
                        allJsonData.add(value.toString());
                    }
                }

                // 根据条件过滤
                List<String> filteredJsonData = filterJsonByConditions(allJsonData, conditions);

                // 排序
                if (sortField != null && !sortField.isEmpty()) {
                    filteredJsonData.sort((json1, json2) ->
                            compareJsonByField(json1, json2, sortField, isAscending));
                }

                // 手动分页
                List<String> resultList = filteredJsonData.stream()
                        .skip(start)
                        .limit(pageSize)
                        .collect(Collectors.toList());

                // 计算总数
                long total = filteredJsonData.size();

                return new PageResult<>(resultList, total, pageNum, pageSize);
            } catch (Exception e) {
                throw new RuntimeException("从Redis分页查询数据失败", e);
            }
        }

        /**
         * 根据多种条件过滤JSON数据
         */
        private List<String> filterJsonByConditions(List<String> jsonList, Map<String, Object> conditions) {
            if (conditions == null || conditions.isEmpty()) {
                return new ArrayList<>(jsonList);
            }

            List<String> filteredList = new ArrayList<>();
            for (String json : jsonList) {
                try {
                    JsonNode jsonNode = objectMapper.readTree(json);
                    boolean isMatch = true;

                    // 遍历所有条件
                    for (Map.Entry<String, Object> entry : conditions.entrySet()) {
                        String field = entry.getKey();
                        Object conditionValue = entry.getValue();

                        // 检查字段是否存在
                        JsonNode fieldNode = jsonNode.get(field);
                        if (fieldNode == null) {
                            isMatch = false;
                            break;
                        }

                        // 处理条件
                        if (conditionValue instanceof Map) {
                            // 复杂条件（包含操作符）
                            @SuppressWarnings("unchecked")
                            Map<String, Object> opMap = (Map<String, Object>) conditionValue;
                            if (!checkCondition(fieldNode, opMap)) {
                                isMatch = false;
                                break;
                            }
                        } else {
                            // 简单条件（默认等于）
                            if (!checkCondition(fieldNode, Collections.singletonMap(OP_EQ, conditionValue))) {
                                isMatch = false;
                                break;
                            }
                        }
                    }

                    if (isMatch) {
                        filteredList.add(json);
                    }
                } catch (Exception e) {
                    // 忽略解析失败的JSON
                }
            }
            return filteredList;
        }

        /**
         * 检查字段是否满足条件
         */
        private boolean checkCondition(JsonNode fieldNode, Map<String, Object> opMap) {
            for (Map.Entry<String, Object> opEntry : opMap.entrySet()) {
                String operator = opEntry.getKey();
                Object value = opEntry.getValue();

                // 根据操作符检查条件
                switch (operator) {
                    case OP_EQ:
                        if (!isEqual(fieldNode, value)) {
                            return false;
                        }
                        break;
                    case OP_NE:
                        if (isEqual(fieldNode, value)) {
                            return false;
                        }
                        break;
                    case OP_GT:
                        if (!isGreaterThan(fieldNode, value)) {
                            return false;
                        }
                        break;
                    case OP_LT:
                        if (!isLessThan(fieldNode, value)) {
                            return false;
                        }
                        break;
                    case OP_GTE:
                        if (!isGreaterThanOrEqual(fieldNode, value)) {
                            return false;
                        }
                        break;
                    case OP_LTE:
                        if (!isLessThanOrEqual(fieldNode, value)) {
                            return false;
                        }
                        break;
                    default:
                        throw new IllegalArgumentException("不支持的操作符: " + operator);
                }
            }
            return true;
        }

        /**
         * 检查是否相等
         */
        private boolean isEqual(JsonNode fieldNode, Object value) {
            if (value == null) {
                return fieldNode.isNull();
            }

            if (fieldNode.isNumber() && value instanceof Number) {
                return fieldNode.numberValue().doubleValue() == ((Number) value).doubleValue();
            } else if (fieldNode.isBoolean() && value instanceof Boolean) {
                return fieldNode.booleanValue() == (Boolean) value;
            } else {
                return fieldNode.asText().equals(value.toString());
            }
        }

        /**
         * 检查是否大于
         */
        private boolean isGreaterThan(JsonNode fieldNode, Object value) {
            if (!fieldNode.isNumber() || !(value instanceof Number)) {
                return false;
            }
            return fieldNode.numberValue().doubleValue() > ((Number) value).doubleValue();
        }

        /**
         * 检查是否小于
         */
        private boolean isLessThan(JsonNode fieldNode, Object value) {
            if (!fieldNode.isNumber() || !(value instanceof Number)) {
                return false;
            }
            return fieldNode.numberValue().doubleValue() < ((Number) value).doubleValue();
        }

        /**
         * 检查是否大于等于
         */
        private boolean isGreaterThanOrEqual(JsonNode fieldNode, Object value) {
            if (!fieldNode.isNumber() || !(value instanceof Number)) {
                return false;
            }
            return fieldNode.numberValue().doubleValue() >= ((Number) value).doubleValue();
        }

        /**
         * 检查是否小于等于
         */
        private boolean isLessThanOrEqual(JsonNode fieldNode, Object value) {
            if (!fieldNode.isNumber() || !(value instanceof Number)) {
                return false;
            }
            return fieldNode.numberValue().doubleValue() <= ((Number) value).doubleValue();
        }

        /**
         * 根据JSON字段排序
         */
        private int compareJsonByField(String json1, String json2, String sortField, boolean isAscending) {
            try {
                JsonNode node1 = objectMapper.readTree(json1);
                JsonNode node2 = objectMapper.readTree(json2);

                JsonNode value1 = node1.get(sortField);
                JsonNode value2 = node2.get(sortField);

                if (value1 == null || value2 == null) {
                    return 0;
                }

                int compareResult;
                if (value1.isNumber() && value2.isNumber()) {
                    compareResult = Double.compare(
                            value1.numberValue().doubleValue(),
                            value2.numberValue().doubleValue()
                    );
                } else if (value1.isTextual() && value2.isTextual()) {
                    compareResult = value1.asText().compareTo(value2.asText());
                } else if (value1.isBoolean() && value2.isBoolean()) {
                    compareResult = Boolean.compare(value1.booleanValue(), value2.booleanValue());
                } else {
                    // 不同类型无法比较
                    return 0;
                }

                return isAscending ? compareResult : -compareResult;
            } catch (Exception e) {
                return 0;
            }
        }

        /**
         * 根据ID获取单个JSON对象
         */
        public String getById(String id) {
            try {
                String key = keyPrefix + ":" + id;
                Object value = redisTemplate.opsForHash().get(key, "data");
                return value != null ? value.toString() : null;
            } catch (Exception e) {
                throw new RuntimeException("从Redis获取对象失败", e);
            }
        }

        /**
         * 批量获取JSON对象
         */
        public List<String> getByIds(List<String> ids) {
            if (CollectionUtils.isEmpty(ids)) {
                return Collections.emptyList();
            }

            List<String> keys = ids.stream()
                    .map(id -> keyPrefix + ":" + id)
                    .collect(Collectors.toList());

            List<String> result = new ArrayList<>();
            for (String key : keys) {
                Object value = redisTemplate.opsForHash().get(key, "data");
                if (value != null) {
                    result.add(value.toString());
                }
            }

            return result;
        }

        /**
         * 删除对象
         */
        public void delete(String id) {
            String key = keyPrefix + ":" + id;
            redisTemplate.opsForSet().remove(indexKey, key);
            redisTemplate.delete(key);
        }

        /**
         * 批量删除对象
         */
        public void batchDelete(List<String> ids) {
            if (CollectionUtils.isEmpty(ids)) {
                return;
            }

            List<String> keys = ids.stream()
                    .map(id -> keyPrefix + ":" + id)
                    .collect(Collectors.toList());

            redisTemplate.opsForSet().remove(indexKey, keys.toArray());
            redisTemplate.delete(keys);
        }

        /**
         * 获取索引集合大小
         */
        public long getIndexSize() {
            Long size = redisTemplate.opsForSet().size(indexKey);
            return size != null ? size : 0;
        }

        /**
         * 删除当前Builder配置的所有相关数据
         */
        public void deleteAll() {
            if (keyPrefix == null || indexKey == null) {
                throw new IllegalStateException("keyPrefix and indexKey must be set before calling deleteAll");
            }

            Set<Object> keys = redisTemplate.opsForSet().members(indexKey);
            if (!CollectionUtils.isEmpty(keys)) {
                redisTemplate.delete(keys.toString());
                redisTemplate.delete(indexKey);
            }

            Set<String> patternKeys = redisTemplate.keys(keyPrefix + ":*");
            if (!CollectionUtils.isEmpty(patternKeys)) {
                redisTemplate.delete(patternKeys);
            }
        }

        /**
         * 根据ID列表删除数据（同时从indexKey集合中移除）
         */
        public void deleteByIds(List<String> ids) {
            if (CollectionUtils.isEmpty(ids)) {
                return;
            }

            List<String> keys = ids.stream()
                    .map(id -> keyPrefix + ":" + id)
                    .collect(Collectors.toList());

            redisTemplate.opsForSet().remove(indexKey, keys.toArray());
            redisTemplate.delete(keys);
        }

        /**
         * 清空indexKey集合但不删除数据
         */
        public void clearIndex() {
            if (indexKey == null) {
                throw new IllegalStateException("indexKey must be set before calling clearIndex");
            }
            redisTemplate.delete(indexKey);
        }

        /**
         * 删除所有数据但不影响indexKey集合
         */
        public void deleteAllData() {
            if (keyPrefix == null) {
                throw new IllegalStateException("keyPrefix must be set before calling deleteAllData");
            }

            Set<Object> keys = redisTemplate.opsForSet().members(indexKey);
            if (!CollectionUtils.isEmpty(keys)) {
                redisTemplate.delete(keys.toString());
            }

            Set<String> patternKeys = redisTemplate.keys(keyPrefix + ":*");
            if (!CollectionUtils.isEmpty(patternKeys)) {
                patternKeys = patternKeys.stream()
                        .filter(key -> !key.equals(indexKey))
                        .collect(Collectors.toSet());

                if (!CollectionUtils.isEmpty(patternKeys)) {
                    redisTemplate.delete(patternKeys);
                }
            }
        }
    }

    /**
     * 分页结果类
     */
    public static class PageResult<String> {
        private List<String> list;
        private long total;
        private int pageNum;
        private int pageSize;
        private int pages;

        public PageResult(List<String> list, long total, int pageNum, int pageSize) {
            this.list = list;
            this.total = total;
            this.pageNum = pageNum;
            this.pageSize = pageSize;
            this.pages = (int) Math.ceil((double) total / pageSize);
        }

        public List<String> getList() { return list; }
        public long getTotal() { return total; }
        public int getPageNum() { return pageNum; }
        public int getPageSize() { return pageSize; }
        public int getPages() { return pages; }

        @Override
        public java.lang.String toString() {
            return "PageResult{" +
                    "list=" + list +
                    ", total=" + total +
                    ", pageNum=" + pageNum +
                    ", pageSize=" + pageSize +
                    ", pages=" + pages +
                    '}';
        }
    }

    /**
     * 快速存储单个对象
     */
    public void storeSingle(String keyPrefix, String indexKey, Object data,
                            Function<Object, String> keyExtractor, long expireTime) {
        builder()
                .keyPrefix(keyPrefix)
                .indexKey(indexKey)
                .dataList(Collections.singletonList(data))
                .keyExtractor(keyExtractor)
                .expireTime(expireTime)
                .store();
    }

    /**
     * 快速读取单个对象
     */
    public String readSingle(String keyPrefix, String id) {
        return builder()
                .keyPrefix(keyPrefix)
                .getById(id);
    }

    /**
     * 快速读取所有对象
     */
    public List<String> readAll(String indexKey) {
        return builder()
                .indexKey(indexKey)
                .pageQuery(1, Integer.MAX_VALUE, null)
                .getList();
    }

    /**
     * 快速分页查询
     */
    public PageResult<String> quickPageQuery(String indexKey, int pageNum, int pageSize, Map<String, Object> conditions) {
        return builder()
                .indexKey(indexKey)
                .pageQuery(pageNum, pageSize, conditions);
    }
}
